package br.com.foxinline.servico;

import br.com.foxinline.enums.Relatorio;
import br.com.foxinline.enums.TipoAverbacao;
import br.com.foxinline.enums.TipoDocumento;
import br.com.foxinline.generico.ServicoGenerico;
import br.com.foxinline.modelo.Averbacao;
import br.com.foxinline.modelo.Imovel;
import br.com.foxinline.modelo.Prefeitura;
import br.com.foxinline.modelo.Proprietario;
import br.com.foxinline.modelo.Requerimento;
import br.com.foxinline.util.Caracter;
import br.com.foxinline.util.Extenso;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;

/**
 *
 * @author luciano
 */
@Stateless
public class AverbacaoServico extends ServicoGenerico<Averbacao> {

    @EJB
    private PrefeituraServico prefeituraService;
//    private ImovelServico imovelServico;

    public AverbacaoServico() {
        super(Averbacao.class);
    }

    @Override
    public void save(Averbacao entity) {
        entity.setDataAverbacao(new Date());
        super.save(entity);
    }

    public List<Averbacao> getPorImovel(Imovel imovel) {
        String sql = "SELECT r FROM Averbacao r WHERE r.imovel= :imovel AND r.finalizado = TRUE order by r.dataAverbacao desc";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("imovel", imovel);

        if (query.getResultList() != null) {
            return (List<Averbacao>) query.getResultList();
        }
        return new ArrayList<Averbacao>();

    }

    public List<Imovel> getPorImovelAverbacao(Averbacao averbacao) {
        String sql = "SELECT i FROM Averbacao a JOIN a.imoveis i WHERE a.id = :id ";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("id", averbacao.getId());

        if (query.getResultList() != null) {
            return (List<Imovel>) query.getResultList();
        }
        return new ArrayList<Imovel>();

    }

    public Averbacao getAverbacaoRequerimento(Requerimento req) {
        Averbacao averbacao;
        String sql = "SELECT a FROM Averbacao a JOIN a.requerimento r WHERE r.id = :id ";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("id", req.getId());

        try {
            averbacao = (Averbacao) query.getResultList().get(0);

        } catch (NoResultException nr) {
            return null;
        } catch (NonUniqueResultException nre) {
            return null;
        } catch (Exception e) {
            return null;
        }

        return averbacao;
    }

    public Long diagQtdAverbacaoPorImovel(Imovel imovel) {
        String sql = "SELECT count(a.id) FROM Averbacao a JOIN a.imovel i "
                + " where i.id = :imovel AND  "
                + " a.finalizado = TRUE";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("imovel", imovel.getId());
        return (Long) query.getSingleResult();
    }

    public List<Proprietario> proprietarios(Imovel imovel) {
        String sql = "SELECT p FROM Imovel i JOIN i.proprietarios p WHERE i.id = :id";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("id", imovel.getId());

        if (query.getResultList() != null) {
            return (List<Proprietario>) query.getResultList();
        }
        return new ArrayList<Proprietario>();

    }

    public void imprimirAverbacao(Averbacao registration, HashMap parametros) {
        if (registration.getAverbacao() != null) {
            registration.setAverbacao(find(registration.getAverbacao().getId()));
        }
        if (registration.getTipoAverbacao().equals(TipoAverbacao.TRANSFERENCIA)) {
            printRegistrationTransferencia(registration, parametros);
        } else if (registration.getTipoAverbacao().equals(TipoAverbacao.MUDANCA_NOME)) {
            printRegistrationMudancaDeNome(registration, parametros);
        } else if (registration.getTipoAverbacao().equals(TipoAverbacao.DESMEMBRAMENTO)) {
            printRegistrationDesmembramento(registration, parametros);
        }
    }

    public String getTextoAverbacao(Averbacao averbacao) {
        if (averbacao.getAverbacao() == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        sb.append("Averb. Nº ");
        sb.append(averbacao.getAverbacao().getId());
        sb.append(", Livro Nº ");
        sb.append(averbacao.getAverbacao().getLivro());
        sb.append(" às fls Nº ");
        sb.append(averbacao.getAverbacao().getFolhas());
        return sb.toString();
    }

    private void printRegistrationTransferencia(Averbacao averbacao, HashMap parametros) {
        printAverbacao(averbacao, getNomeProprietarios(averbacao.getTransmitente()), getNomeProprietarios(averbacao.getAdquirente()), parametros);
    }

    private void printRegistrationMudancaDeNome(Averbacao averbacao, HashMap parametros) {

        printAverbacao(averbacao, averbacao.getNomeAnterior(), averbacao.getNomeAtual(), parametros);
    }

    private void printAverbacao(Averbacao averbacao, String foreiro, String adquirente, HashMap parametros) {
//        parametros = new HashMap();
        StringBuilder texto = new StringBuilder();

        texto.append("    Certifico de ordem do Sr. Prefeito Municipal e à vista do processo e demais assentamentos nesta Repartição,");
        texto.append(" que da(s) Averbação ( ");
        texto.append(getTextoAverbacao(averbacao));
        texto.append(" )foreiro (a) (");
        texto.append(inBoldAndUnderline(foreiro));
        texto.append(") foi transmitida, a seu pedido por petição número ");
        texto.append(averbacao.getNumeroPeticao());
        texto.append(" de ");
        texto.append(formatDate(averbacao.getDataPeticao()));
        texto.append(" para o(a) Sr.: (");
        texto.append(inBoldAndUnderline(adquirente));
        texto.append("), conforme (Instrumento Público) ");
        texto.append(averbacao.getInstrumentoPublico());
        texto.append(", lavrado no ");
        texto.append(averbacao.getCartorio());
        texto.append(", (Livro Nº ");
        texto.append(averbacao.getLivroCartorio());
        texto.append(", fls Nº ");
        texto.append(averbacao.getFolhasCartorio());
        texto.append(") a área de (");
        texto.append(averbacao.getImovel().getDimensoes().getAreaTerreno());
        texto.append("m2): com a seguinte delimitação");

        StringBuilder dimensao = new StringBuilder();
        dimensao.append(" FRENTE: ");
        dimensao.append(averbacao.getImovel().getFrenteRua());
        dimensao.append(", LADO DIREITO: ");
        dimensao.append(averbacao.getImovel().getLadoDireitoRua());
        dimensao.append(", LADO ESQUERDO: ");
        dimensao.append(averbacao.getImovel().getLadoEsquerdoRua());
        dimensao.append(", FUNDO: ");
        dimensao.append(averbacao.getImovel().getFundoRua());

        texto.append(inBoldAndUnderline(dimensao.toString()));

        texto.append(" tendo sido feita a respectiva averbação na(s) Cartas de Aforamento supra citada(s) e no livro próprio desta Repartição em ");
        texto.append(dataPorExtenso(averbacao.getDataAverbacao()));
        texto.append(". <br/>");
        texto.append("    O novo foreiro sujeita-se a todas disposições contidas na legislação municipal sobre o assunto e inerentes às Cartas de Aforamento, salientando-se as seguintes obrigações:<br/>");
        texto.append("   1. Fica por se e seus herdeiros obrigados ao pagamento anual do fôro de R$ 0,020 centavos por metro quadrado.<br/>");
        texto.append("   2. Satisfarão pagamento dos fôros dentro de cada ano em curso, exceto o primeiro pagamento que é feito antes da expedição do presente título.<br/>");
        texto.append("   3. Na falta de pagamento no prazo acima marcado, pagará mais a multa de 10%.<br/>");
        texto.append("   4. O fôro do primeiro ano integral qualquer que seja o mês em que se utilize aforamento.<br/>");
        texto.append("   5. Perderá o direito do aforamento o terreno, voltando ele ao domínio útil do Município, depois de processado o comisso, quando não edificado ou beneficiado se deixar de pagar o fôro de três anos consecutivos.<br/>");
        texto.append("   6. Reconhece não obstante a pena de comisso, o dever em que fica de pagar todos os fôros e multas devidas pelo tempo em que esteve em posse do terreno.<br/>");
        texto.append("   7. Além dos foros e multas da cláusula terceira pagará mais a multa especial R$ pela falta de pagamento por três anos consecutivos, dos foros do seu terreno em que tiver construção ou benefícios.<br/>");
        texto.append("   8. Só poderá transferir o domínio útil do terreno ou parte dele, mediante licença do Prefeito Municipal, a quem a solicitará previamente.<br/>");
        texto.append("   9. Ser-lhe-á facultada recisão deste contrato, quando isso lhe convenha certificando o Prefeito desta sua resolução e pagando previamente todos os fôros e taxas devidas pela posse anterior.<br/>");
        texto.append("   10. Quando realizar a transferência do domínio útil de seu terreno por venda ou docação pagamento ou outra forma de transferência a que o Município por seu Prefeito renunciar ao direito de opção pagará o laudêmio % sobre o preço do terreno observando o valor real.<br/>");
        texto.append("   11. O aforamento não poderá, em tempo algum ser resgatado pelo foreiro.<br/>");
        texto.append("   12. O foreiro se obriga beneficiar ou construir em seu terreno, nos termos e condições expressas na legislação sob pena das taxas neles consignadas.<br/><br/>");
        texto.append("    E por que pelo mesmo ");
        texto.append(inBoldAndUnderline(foreiro));
        texto.append(" fossem aceitas todas as certidões expostas demais disposições legais obrigando para seu cumprimento todos os seus bens presentes e futuros. Assinam a presente Certidão com o Direito e Encarregado - SCC do DOP (Departamento de Obras Públicas).<br/>");
        texto.append("    Datada e passada em Parnaíba ");
        texto.append(dataPorExtenso(averbacao.getDataAverbacao()));

        StringBuilder rodape = new StringBuilder("Registrada ao Livro Nº ");
        rodape.append(averbacao.getLivro());
        rodape.append(" às folhas ");
        rodape.append(averbacao.getFolhas());
        rodape.append(" em ");
        rodape.append(formatDate(averbacao.getDataAverbacao()));

        Prefeitura prefeitura = prefeituraService.find(null);

        parametros.put("texto", texto.toString());
        parametros.put("rodape", inBold(rodape.toString()));
        parametros.put("numero", averbacao.getId().toString());

        if (prefeitura != null) {
            parametros.put("diretora", prefeitura.getNomeDiretoraDepartamentoTerras());
            parametros.put("secretaria", prefeitura.getSecretarioRegularizacaoFundiaria());
        } else {
            parametros.put("diretora", "");
            parametros.put("secretaria", "");
        }

        parametros.put("situacao", averbacao.getSituacao());

        RelatorioServico.genReport(parametros, null, Relatorio.AVERBACAO_TRANSFERENCIA);
    }

    private void printRegistrationDesmembramento(Averbacao registration, HashMap parametros) {
        printAverbacaoDesmembramento(registration, null, null, parametros);
    }

    private void printAverbacaoDesmembramento(Averbacao averbacao, String foreiro, String adquirente, HashMap parametros) {
//        parametros = new HashMap();
        List<Proprietario> proprietarios = new ArrayList<Proprietario>();
        StringBuilder texto = new StringBuilder();

        texto.append("    Certifico de ordem do Sr. Prefeito Municipal e à vista do processo e demais assentamentos nesta Repartição,");
        texto.append(" que da(s) Averbação ( ");
        texto.append(inBold(averbacao.getTipoAverbacao().getNome()));
//        texto.append(" )foreiro (a) (");
//        texto.append(inBoldAndUnderline(foreiro));
        texto.append(") foi transmitida, a seu pedido por petição aos senhores ");
        for (Imovel imovel : getPorImovelAverbacao(averbacao)) {

            proprietarios = proprietarios(imovel);
            texto.append(inBold(getNomeProprietarios(proprietarios)) + " totalizando uma área de " + imovel.getDimensoes().getAreaTerreno() + " m² , ");

        }


//        texto.append(averbacao.getImovel());
//        texto.append(averbacao.getNumeroPeticao());
//        texto.append(" de ");
//        texto.append(formatDate(averbacao.getDataPeticao()));
//        texto.append(" para o(a) Sr.: (");
//        texto.append(inBoldAndUnderline(adquirente));
//        texto.append("), conforme (Instrumento Público) ");
//        texto.append(averbacao.getInstrumentoPublico());
//        texto.append(", lavrado no ");
//        texto.append(averbacao.getCartorio());
//        texto.append(", (Livro Nº ");
//        texto.append(averbacao.getLivroCartorio());
//        texto.append(", fls Nº ");
//        texto.append(averbacao.getFolhasCartorio());
//        texto.append(") a área de (");
//        texto.append(averbacao.getImovel().getDimensoes().getAreaTerreno());
//        texto.append("m2): com a seguinte delimitação");
//
//        StringBuilder dimensao = new StringBuilder();
//        dimensao.append(" FRENTE: ");
//        dimensao.append(averbacao.getImovel().getFrenteRua());
//        dimensao.append(", LADO DIREITO: ");
//        dimensao.append(averbacao.getImovel().getLadoDireitoRua());
//        dimensao.append(", LADO ESQUERDO: ");
//        dimensao.append(averbacao.getImovel().getLadoEsquerdoRua());
//        dimensao.append(", FUNDO: ");
//        dimensao.append(averbacao.getImovel().getFundoRua());

//        texto.append(inBoldAndUnderline(dimensao.toString()));

        texto.append(" tendo sido feita a respectiva averbação na(s) Cartas de Aforamento supra citada(s) e no livro próprio desta Repartição em ");
        texto.append(dataPorExtenso(averbacao.getDataAverbacao()));
        texto.append(". <br/>");
        texto.append("    O novo foreiro sujeita-se a todas disposições contidas na legislação municipal sobre o assunto e inerentes às Cartas de Aforamento, salientando-se as seguintes obrigações:<br/>");
        texto.append("   1. Fica por se e seus herdeiros obrigados ao pagamento anual do fôro de R$ 0,020 centavos por metro quadrado.<br/>");
        texto.append("   2. Satisfarão pagamento dos fôros dentro de cada ano em curso, exceto o primeiro pagamento que é feito antes da expedição do presente título.<br/>");
        texto.append("   3. Na falta de pagamento no prazo acima marcado, pagará mais a multa de 10%.<br/>");
        texto.append("   4. O fôro do primeiro ano integral qualquer que seja o mês em que se utilize aforamento.<br/>");
        texto.append("   5. Perderá o direito do aforamento o terreno, voltando ele ao domínio útil do Município, depois de processado o comisso, quando não edificado ou beneficiado se deixar de pagar o fôro de três anos consecutivos.<br/>");
        texto.append("   6. Reconhece não obstante a pena de comisso, o dever em que fica de pagar todos os fôros e multas devidas pelo tempo em que esteve em posse do terreno.<br/>");
        texto.append("   7. Além dos foros e multas da cláusula terceira pagará mais a multa especial R$ pela falta de pagamento por três anos consecutivos, dos foros do seu terreno em que tiver construção ou benefícios.<br/>");
        texto.append("   8. Só poderá transferir o domínio útil do terreno ou parte dele, mediante licença do Prefeito Municipal, a quem a solicitará previamente.<br/>");
        texto.append("   9. Ser-lhe-á facultada recisão deste contrato, quando isso lhe convenha certificando o Prefeito desta sua resolução e pagando previamente todos os fôros e taxas devidas pela posse anterior.<br/>");
        texto.append("   10. Quando realizar a transferência do domínio útil de seu terreno por venda ou docação pagamento ou outra forma de transferência a que o Município por seu Prefeito renunciar ao direito de opção pagará o laudêmio % sobre o preço do terreno observando o valor real.<br/>");
        texto.append("   11. O aforamento não poderá, em tempo algum ser resgatado pelo foreiro.<br/>");
        texto.append("   12. O foreiro se obriga beneficiar ou construir em seu terreno, nos termos e condições expressas na legislação sob pena das taxas neles consignadas.<br/><br/>");
//        texto.append("    E por que pelo mesmo ");
//        texto.append(inBoldAndUnderline(foreiro));
//        texto.append(" fossem aceitas todas as certidões expostas demais disposições legais obrigando para seu cumprimento todos os seus bens presentes e futuros. Assinam a presente Certidão com o Direito e Encarregado - SCC do DOP (Departamento de Obras Públicas).<br/>");
//        texto.append("    Datada e passada em Parnaíba ");
//        texto.append(dataPorExtenso(averbacao.getDataAverbacao()));

        StringBuilder rodape = new StringBuilder();
//        rodape.append(averbacao.getLivro());
        rodape.append(" Averbação de Desmembramento realizado em ");
//        rodape.append(averbacao.getFolhas());
//        rodape.append(" em ");
        rodape.append(formatDate(averbacao.getDataAverbacao()));

        Prefeitura prefeitura = prefeituraService.find(null);

        parametros.put("texto", texto.toString());
        parametros.put("rodape", inBold(rodape.toString()));
        parametros.put("numero", averbacao.getId().toString());

        if (prefeitura != null) {
            parametros.put("diretora", prefeitura.getNomeDiretoraDepartamentoTerras());
            parametros.put("secretaria", prefeitura.getSecretarioRegularizacaoFundiaria());
        } else {
            parametros.put("diretora", "");
            parametros.put("secretaria", "");
        }

        parametros.put("situacao", averbacao.getSituacao());

        RelatorioServico.genReport(parametros, null, Relatorio.AVERBACAO_DESMEMBRAMENTO);
    }

    public String getNomeProprietarios(List<Proprietario> proprietarios) {
        StringBuilder sb = new StringBuilder();
        Proprietario proprietario;

        for (int i = 0; i < proprietarios.size(); i++) {
            if (proprietarios.size() > 1 && i > 0) {
                if (i < proprietarios.size() - 1) {
                    sb.append(", ");
                } else {
                    sb.append(" e ");
                }
            }

            proprietario = proprietarios.get(i);

            if (proprietarios != null && proprietario != null) {

                proprietario = proprietarios.get(i);

                if (proprietario.getTipoDocumento() != null) {
                    if (proprietario.getTipoDocumento().equals(TipoDocumento.CPF)) {
                        if (proprietario.getNome() != null && !proprietario.getNome().isEmpty()) {
                            sb.append(proprietario.getNome());
                        }
                    } else {
                        if (proprietario.getNomeFantasia() != null && !proprietario.getNomeFantasia().isEmpty()) {
                            sb.append(proprietario.getNomeFantasia());
                        }
                    }
                } else {
                    if (proprietario.getNome() != null && !proprietario.getNome().isEmpty()) {
                        sb.append(proprietario.getNome());
                    } else if (proprietario.getNomeFantasia() != null && !proprietario.getNomeFantasia().isEmpty()) {
                        sb.append(proprietario.getNomeFantasia());
                    }
                }
            }
        }
        return sb.toString().toUpperCase();
    }

    public String getDocumentoProprietarios(List<Proprietario> proprietarios) {
        StringBuilder sb = new StringBuilder();
        Proprietario proprietario;

        for (int i = 0; i < proprietarios.size(); i++) {
            if (proprietarios.size() > 1 && i > 0) {
                if (i < proprietarios.size() - 1) {
                    sb.append(", ");
                } else {
                    sb.append(" e ");
                }
            }

            proprietario = proprietarios.get(i);

            if (proprietarios != null && proprietario != null) {

                if (proprietario.getTipoDocumento() == null) {

                    if (proprietario.getCpf() != null && !proprietario.getCpf().isEmpty()) {

                        proprietario.setTipoDocumento(TipoDocumento.CPF);
                    } else if (proprietario.getCnpj() != null && !proprietario.getCnpj().isEmpty()) {

                        proprietario.setTipoDocumento(TipoDocumento.CNPJ);
                    } else {
                        proprietario.setTipoDocumento(TipoDocumento.CPF);
                    }
                }

                if (proprietario.getTipoDocumento() != null && proprietario.getTipoDocumento().equals(TipoDocumento.CPF)) {

                    if (proprietario.getCpf() != null && !proprietario.getCpf().isEmpty()) {
                        sb.append(Caracter.addMask(proprietario.getCpf(), Caracter.cpfMask));
                    } else {
                        sb.append("Sem documento");
                    }
                } else if (proprietario.getTipoDocumento() != null && proprietario.getTipoDocumento().equals(TipoDocumento.CNPJ)) {

                    if (proprietario.getCnpj() != null && !proprietario.getCnpj().isEmpty()) {
                        sb.append(Caracter.addMask(proprietario.getCnpj(), Caracter.cnpjMask));
                    } else {
                        sb.append("Sem documento");
                    }
                }
            }
        }
        return sb.toString().toUpperCase();
    }

    public String formatDate(Date date) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
        if (date != null) {
            return dateFormat.format(date);
        }
        return null;
    }

    private String inBoldAndUnderline(String texto) {
        StringBuilder sb = new StringBuilder("<style isBold='true' isUnderline='true' pdfFontName='Helvetica-Bold'>");
        sb.append(texto);
        sb.append("</style>");
        return sb.toString();
    }

    private String inBold(String texto) {
        StringBuilder sb = new StringBuilder("<style isBold='true' pdfFontName='Helvetica-Bold'>");
        sb.append(texto);
        sb.append("</style>");
        return sb.toString();
    }

    private String getDimensaoPorExtenso(String number) {
        StringBuilder result = new StringBuilder();
        try {
            BigDecimal n = new BigDecimal(number);
            Extenso e = new Extenso(n);
            result.append(e.toString());
            result.append(" metros (");
            result.append(e.DecimalFormat());
            result.append("m);");
            return result.toString();
        } catch (Exception e) {
            System.err.println(e);
        }
        return "";
    }

    private String dataPorExtenso(Date date) {
        DateFormat dfmt = new SimpleDateFormat("d 'de' MMMM 'de' yyyy");
        return dfmt.format(date);

    }
}
